﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Text;
using System.Windows.Forms;

namespace ProfileCare
{
    public partial class frmMain : Form
    {
        string root = Environment.GetEnvironmentVariable("USERPROFILE").ToLower();
        // Bijvoorbeeld C:\users\erik
        DataTable fileTable;
        long profSize; // bytes
        ArrayList ExcludeFromRoaming;
        // Data structure to hold names of subfolders to be 
        // examined for files.
        Stack<string> dirs;

        public frmMain()
        {
            InitializeComponent();
            dirs = new Stack<string>(20);
            fileTable = new DataTable();
            fileTable.Columns.Add("File", typeof(string));
            fileTable.Columns.Add("Size", typeof(long));
            comboBoxSize.SelectedIndex = 2;
            ExcludeFromRoaming = ExclusionList();
            fillForm();
        }

        void fillForm()
        {
            dataGridViewFiles.Rows.Clear();
            fileTable.Clear();
            labelMaxSize.Text = getMaxProfileSize();
            TraverseRoamingProfile();
            fillDataGridView();
            labelCurrentSize.Text = ConvertBytesToKilobytes(profSize).ToString();
        }

        // Traverses profile folder and adds files and sizes to datatable
        void TraverseRoamingProfile()
        {
            profSize = 0;
            if (!System.IO.Directory.Exists(root))
            {
                throw new ArgumentException();
            }
            dirs.Push(root);

            while (dirs.Count > 0)
            {
                string currentDir = dirs.Pop();

                    if (String.Equals(currentDir.ToLower(), root + @"\appdata", StringComparison.CurrentCultureIgnoreCase))
                    {
                        // Files in appdata are not synchronised
                        // Only subdirs of appdata are processed
                        getSubDirs(currentDir);
                    }
                    else
                    {
                        if (currentDir.ToLower().IndexOf(root + @"\appdata\", StringComparison.CurrentCultureIgnoreCase) > -1)
                        {
                            if (String.Equals(currentDir.ToLower(), root + @"\appdata\roaming", StringComparison.CurrentCultureIgnoreCase))
                            {
                                getSubDirs(currentDir);
                                getFiles(currentDir);
                            }
                            else
                            {
                                if (currentDir.ToLower().IndexOf(root + @"\appdata\roaming\", StringComparison.CurrentCultureIgnoreCase) > -1)
                                {
                                    bool excluded = false;
                                    // If folder is in Exclusion list, Skip folder from processing
                                    foreach (string folder in ExcludeFromRoaming)
                                    {
                                        string excludedFolder = root + @"\" + folder.ToLower();
                                        if (String.Equals(currentDir.ToLower(), excludedFolder, StringComparison.CurrentCultureIgnoreCase))
                                        {
                                            excluded = true;
                                            continue;
                                        }
                                    }
                                    if (!excluded)
                                    {
                                        // Process this folder
                                        //MessageBox.Show(currentDir);
                                        getSubDirs(currentDir);
                                        getFiles(currentDir);
                                    }
                                }
                                else
                                {
                                    // Do nothing
                                }
                            }
                        }
                        else
                        {
                            getSubDirs(currentDir);
                            getFiles(currentDir);
                        }
                    }
            }
        }

        // get files in currentdir and put them in datatable
        void getFiles(string currentDir)
        {
            string[] files = null;
            int rootLength = root.Length;
            try
            {
                files = System.IO.Directory.GetFiles(currentDir);
            }

            catch (UnauthorizedAccessException e)
            {
                // Console.WriteLine(e.Message);
            }

            catch (System.IO.DirectoryNotFoundException e)
            {
                // Console.WriteLine(e.Message);
            }
            // Perform the required action on each file here. 
            // Modify this block to perform your required task. 
            if (files != null)
            {
                foreach (string file in files)
                {
                    try
                    {
                        // Perform whatever action is required in your scenario.
                        System.IO.FileInfo fi = new System.IO.FileInfo(file);

                        // Examen files in root dir for ntuser.* files
                        if (String.Equals(currentDir.ToLower(), root, StringComparison.CurrentCultureIgnoreCase))
                        {
                            if (file.IndexOf(root + @"\ntuser.", StringComparison.CurrentCultureIgnoreCase) == 0)
                            {
                                if (String.Equals(fi.Name, "ntuser.dat", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    // Only add to profile size, don't list.
                                    profSize += fi.Length;
                                }
                                else if (String.Equals(fi.Name, "ntuser.ini", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    // Only add to profile size, don't list.
                                    profSize += fi.Length;
                                }
                                else if (String.Equals(fi.Name, "ntuser.pol", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    // Only add to profile size, don't list.
                                    profSize += fi.Length;
                                }
                                else
                                {
                                    // Do nothing. The other ntuser files are not synchronised
                                }
                            }
                        }
                        else
                        {
                            string temp = fi.FullName.Substring(rootLength + 1);
                            fileTable.Rows.Add(temp, fi.Length);
                            profSize += fi.Length;
                        }
                    }
                    catch (System.IO.FileNotFoundException e)
                    {
                        // If file was deleted by a separate application 
                        //  or thread since the call to TraverseTree() 
                        // then just continue.
                        // Console.WriteLine(e.Message);
                        continue;
                    }
                }
            }
        }

        // get subdirs of currentdir
        void getSubDirs(string currentDir)
        {
            string[] subDirs = null;
            try
            {
                subDirs = System.IO.Directory.GetDirectories(currentDir);
            }
            // An UnauthorizedAccessException exception will be thrown if we do not have 
            // discovery permission on a folder or file. It may or may not be acceptable  
            // to ignore the exception and continue enumerating the remaining files and  
            // folders. It is also possible (but unlikely) that a DirectoryNotFound exception  
            // will be raised. This will happen if currentDir has been deleted by 
            // another application or thread after our call to Directory.Exists. The  
            // choice of which exceptions to catch depends entirely on the specific task  
            // you are intending to perform and also on how much you know with certainty  
            // about the systems on which this code will run. 
            catch (UnauthorizedAccessException e)
            {
                // Console.WriteLine(e.Message);
                // continue;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                // Console.WriteLine(e.Message);
                // continue;
            }

            // Push the subdirectories onto the stack for traversal. 
            // This could also be done before handing the files. 
            if (subDirs != null)
            {
                foreach (string str in subDirs)
                    dirs.Push(str);
            }
        }

        // Read maxprofilesize from registry
        string getMaxProfileSize()
        {
            string maxSize = "No Limit";
            // string value = "NoDriveTypeAutoRun";
            string value = "MaxProfileSize";
            string Key = "HKEY_CURRENT_USER" + @"\Software\Microsoft\Windows\CurrentVersion\Policies\System";

            try
            {
                int maxProfileSize = (int)Registry.GetValue(Key, value, -1);
                maxSize = maxProfileSize.ToString();
            }
            catch
            {
                maxSize = "No Limit";
            }
            return maxSize;
        }

        ArrayList ExclusionList()
        {
            ArrayList exclusionList = new ArrayList();
            string value = "ExcludeProfileDirs";
            string Key = "HKEY_CURRENT_USER" + @"\Software\Policies\Microsoft\Windows\System";
            // string Key = "HKEY_CURRENT_USER" + @"\Software\ColdGroundCode\ProfileCare";
            try
            {
                string ExcludeProfileDirs = (string)Registry.GetValue(Key, value, "No exclusions");
                if (ExcludeProfileDirs != null)
                {
                    string[] excludeDirs = ExcludeProfileDirs.Split(';');
                    foreach (string folder in excludeDirs)
                    {
                        exclusionList.Add(folder);
                    }
                }
            }
            catch
            {
                exclusionList.Add("No exclusions");
            }

            exclusionList.Sort();
            return exclusionList;
        }

        void showExcludeProfileDirs(ArrayList exclusionList)
        {
            frmExcludedDirs frmExclusions = new frmExcludedDirs(exclusionList);
            frmExclusions.Show();
        }

        // convert bytes to KiloBytes
        Int32 ConvertBytesToKilobytes(long bytes)
        {
            return Convert.ToInt32(bytes / 1024f);
        }

        void showExcludedFoldersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showExcludeProfileDirs(ExclusionList());
        }

        void openFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Int32 selectedRowCount =
                dataGridViewFiles.Rows.GetRowCount(DataGridViewElementStates.Selected);
            if (selectedRowCount > 0)
            {
                string file = "";

                for (int i = 0; i < selectedRowCount; i++)
                {
                    file = root + @"\" + dataGridViewFiles.SelectedRows[i].Cells[0].Value.ToString();
                    string path = Path.GetDirectoryName(file);

                    try
                    {
                        // MessageBox.Show(path);
                        openFolder(path);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }

        }

        void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Int32 selectedRowCount =
            dataGridViewFiles.Rows.GetRowCount(DataGridViewElementStates.Selected);

            if (selectedRowCount > 0)
            {
                string file = "";
                long size = 0;
                DialogResult response = MessageBox.Show("Are you sure to delete : " + selectedRowCount + " file(s)?", "Delete file(s)?",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question,
                        MessageBoxDefaultButton.Button2);

                if (response == DialogResult.Yes)
                {
                    for (int i = 0; i < selectedRowCount; i++)
                    {
                        file = root + @"\" + dataGridViewFiles.SelectedRows[i].Cells[0].Value.ToString();
                        size = 1024 * Convert.ToInt64(dataGridViewFiles.SelectedRows[i].Cells["size"].Value); // Bytes
                        if (deleteFile(file, size))
                        {
                            // remove row from datagridview
                            dataGridViewFiles.Rows.Remove(dataGridViewFiles.SelectedRows[0]);
                            // remove row from filetable datatable
                            DataRow[] foundRows;
                            foundRows = fileTable.Select("File = '" + dataGridViewFiles.SelectedRows[i].Cells[0].Value.ToString() + "'");
                            foreach (DataRow row in foundRows)
                            {
                                // MessageBox.Show(row[0].ToString());
                                fileTable.Rows.Remove(row);
                            }
                        }
                    }
                }
            }
        }

        // Delete file
        bool deleteFile(string file, long size)
        {
            try
            {
                // delete file from filesystem
                System.IO.File.Delete(file);
                profSize -= size;
                labelCurrentSize.Text = ConvertBytesToKilobytes(profSize).ToString();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }

        void buttonOk_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAbout about = new frmAbout();
            about.Show();
        }

        void buttonRefresh_Click(object sender, EventArgs e)
        {
            fillForm();
        }

        // fill datagridview with datatable
        void fillDataGridView()
        {
            dataGridViewFiles.Rows.Clear();
            long minSize = Convert.ToInt64(comboBoxSize.SelectedItem) * 1024;
            // MessageBox.Show(minSize.ToString());
            foreach (DataRow row in fileTable.Rows)
            {
                long fileSize = Convert.ToInt64(row["Size"]);
                // MessageBox.Show(row.Cells[1].Value.ToString());
                if (fileSize > minSize)
                {
                    Int32 kbSize = ConvertBytesToKilobytes(fileSize);
                    dataGridViewFiles.Rows.Add(row["File"], kbSize);
                }
            }
            dataGridViewFiles.Sort(Size, ListSortDirection.Descending);
        }

        // Open folder in explorer
        void openFolder(string folder)
        {
            try
            {
                Process.Start(folder);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void comboBoxSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            fillDataGridView();
        }

        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var result = new StringBuilder();
            for (int i = 0; i < fileTable.Columns.Count; i++)
            {
                result.Append(fileTable.Columns[i].ColumnName);
                result.Append(i == fileTable.Columns.Count - 1 ? "\n" : ";");
            }

            foreach (DataRow row in fileTable.Rows)
            {
                for (int i = 0; i < fileTable.Columns.Count; i++)
                {
                    result.Append(row[i].ToString());
                    result.Append(i == fileTable.Columns.Count - 1 ? "\n" : ";");
                }
            }
            saveToFile(result);
        }

        void saveToFile(StringBuilder fileList)
        {
            // Displays a SaveFileDialog so the user can save the Image
            // assigned to Button2.
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "CSV|*.csv|Text|*.txt";
            saveFileDialog1.Title = "Save to File";
            saveFileDialog1.ShowDialog();

            // If the file name is not an empty string open it for saving.
            if (saveFileDialog1.FileName != "")
            {
                // Saves the Image via a FileStream created by the OpenFile method.
                System.IO.File.WriteAllText(saveFileDialog1.FileName, fileList.ToString());
            }

        }
    }
}
